package org.longteng.sys;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.UUID;

/**
 * 同步服务器系统时间
 */
@Slf4j
public class SynServerDateTimeUtils {
    public static final String Time_Pattern = "HH:mm:ss.SSS";
    public static final String Day_Pattern = "yyyy-MM-dd";
    public static final String Date_Time_Pattern = "yyyy-MM-dd HH:mm:ss.SSS";

    /**
     * 修改系统时间
     *
     * @param timescale  UTC时间戳
     */
    public static void upServerSysDateTime(long timescale) {
        if (timescale <= 0) {
            throw new RuntimeException("输入时间戳无效。");
        }
        Date t = new Date(timescale);

        SimpleDateFormat localDateFormater = new SimpleDateFormat(Day_Pattern);
        localDateFormater.setTimeZone(TimeZone.getDefault());
        String dataStr = localDateFormater.format(t);

        SimpleDateFormat localTimeFormater = new SimpleDateFormat(Time_Pattern);
        localTimeFormater.setTimeZone(TimeZone.getDefault());
        String timeStr = localTimeFormater.format(t);
        upServerSysDateTime(dataStr, timeStr);
    }

    /**
     * 修改系统时间
     * yyyy-MM-dd HH:mm:ss
     *
     * @param dataStr 2017-11-11   yyyy-MM-dd
     * @param timeStr 11:11:11     HH:mm:ss
     */
    public static void upServerSysDateTime(String dataStr, String timeStr) {
        try {
            // Window 系统
            if (SysExecCmdUtil.osType == 1) {
                SimpleDateFormat localTimeFormater = new SimpleDateFormat(Date_Time_Pattern);
                localTimeFormater.setTimeZone(TimeZone.getDefault());
                Date t = localTimeFormater.parse(dataStr + " " + timeStr);
                Calendar cal = Calendar.getInstance(TimeZone.getDefault());
                cal.setTime(t);

                // windows 已不通过指令修改日期，用dll
                JnaWindowsSetSystemTime jnaWindowsSetSystemTime = new JnaWindowsSetSystemTime();
                boolean upOk = jnaWindowsSetSystemTime.SetLocalTime((short) cal.get(Calendar.YEAR)
                        , (short) cal.get(Calendar.MONTH)
                        , (short) cal.get(Calendar.DATE)
                        , (short) cal.get(Calendar.HOUR)
                        , (short) cal.get(Calendar.MINUTE)
                        , (short) cal.get(Calendar.SECOND)
                        , (short) cal.get(Calendar.MILLISECOND)
                );

                log.debug("windows 时间修改：{}", upOk);
            } else if (SysExecCmdUtil.osType == 2 || SysExecCmdUtil.osType == 3) {
                // Linux 系统 格式：yyyy-MM-dd HH:mm:ss   date -s "2017-11-11 11:11:11"
                FileWriter excutefw = new FileWriter("/usr/updateSysTime.sh");
                BufferedWriter excutebw = new BufferedWriter(excutefw);
                excutebw.write("date -s \"" + dataStr + " " + timeStr + "\"\r\n");
                excutebw.close();
                excutefw.close();
                String cmd_date = "sh /usr/updateSysTime.sh";
                String res = runLinuxAndResult(cmd_date);
                System.out.println("cmd :" + cmd_date + " date :" + dataStr + " time :" + timeStr);
                System.out.println("linux 时间修改" + res);
            } else {
                System.out.println("操作系统无法识别");
            }
        } catch (Exception e) {
            log.error("修改系统时间发生错误.", e);
        }
    }

    /**
     * 执行 脚本命令  关心结果
     * <br>先要在linux系统设置：
     * <br>root用户执行：chmod 4755 /bin/date
     * <br>备注：也就是给date命令增加s权限位即设置setuid(4000)，这样普通用户就可以执行date命令了
     *
     * @param cmd
     * @return
     */
    private static String runLinuxAndResult(String cmd) throws IOException {
        String ret;

        String uuid = UUID.randomUUID().toString().replace("-", "");
        String tempFileName = "./temp" + uuid + ".sh";
        try {
            if (SysExecCmdUtil.osType == 2 || SysExecCmdUtil.osType == 3) {
                try (FileWriter excutefw = new FileWriter(tempFileName);
                     BufferedWriter excutebw = new BufferedWriter(excutefw);) {
                    excutebw.write(cmd + "\n");
                    excutebw.flush();
                }

                String command = "bash " + tempFileName;
                ret = SysExecCmdUtil.exeProcess(command, null);

                log.info("exec [ {} ]  OK , result : [ {} ]", cmd, ret);
            } else {
                throw new IOException("不支持的操作系统类型");
            }
        } catch (Exception e) {
            log.error("exec [ {} ]  fail : {}", cmd, e.getMessage());
            throw new IOException(e);
        } finally {
            Files.deleteIfExists(Paths.get(tempFileName));
        }
        return ret;
    }

    /**
     * UTC时间转成本成时间
     * <br>如：在通过baidu接口取时间来同步到本地机器时用到这个转换
     *
     * @param utcTime     Mon, 24 Apr 2023 07:40:01 GMT
     * @param timePattern yyyy-MM-dd HH:mm:ss.SSSXXX
     */
    public static String utcToLocal(String utcTime, String timePattern) {
        SimpleDateFormat utcFormater = new SimpleDateFormat(timePattern);
        utcFormater.setTimeZone(TimeZone.getTimeZone("UTC"));//时区定义并进行时间获取
        Date gpsUTCDate = null;
        try {
            gpsUTCDate = utcFormater.parse(utcTime);
        } catch (ParseException e) {
            log.error("UTC时间载入错误.", e);
            return utcTime;
        }
        SimpleDateFormat localFormater = new SimpleDateFormat(timePattern);
        localFormater.setTimeZone(TimeZone.getDefault());
        String localTime = localFormater.format(gpsUTCDate.getTime());
        return localTime;
    }


}
